namespace V2TEK.NET.SH.Silverlight.Calendar
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Runtime.InteropServices;

    internal abstract class CalendarPeriod
    {
        protected WorkCalendar _calendar;
        protected bool _isWorking;
        private bool _standard;
        private IList<WorkingTime> _workingTimes;

        public CalendarPeriod(WorkCalendar calendar, bool working)
        {
            this._calendar = calendar;
            this._workingTimes = new List<WorkingTime>(2);
            this._isWorking = working;
            if (working)
            {
                WorkingTime item = new WorkingTime(new TimeSpan(8, 0, 0), new TimeSpan(12, 0, 0));
                WorkingTime time2 = new WorkingTime(new TimeSpan(13, 0, 0), new TimeSpan(0x11, 0, 0));
                this._workingTimes.Add(item);
                this._workingTimes.Add(time2);
            }
        }

        internal abstract DateTime Add(DateTime time, ref long duration);
        internal DateTime AddWorkInDay(DateTime time, ref long duration)
        {
            if (duration == 0L)
            {
                return time;
            }
            long ticks = time.Ticks;
            long num2 = ticks - (ticks % 864000000000);
            if (!this._isWorking)
            {
                return new DateTime(num2 + WorkCalendar.OneDay);
            }
            long num3 = ticks - num2;
            long oneDay = WorkCalendar.OneDay;
            bool flag = true;
            int count = this._workingTimes.Count;
            for (int i = 0; i < count; i++)
            {
                WorkingTime time2 = this._workingTimes[i];
                long num7 = time2._startTime;
                if (flag)
                {
                    if (num3 > time2._endTime)
                    {
                        continue;
                    }
                    flag = false;
                    if (num3 < num7)
                    {
                        num3 = num7;
                    }
                }
                else
                {
                    num3 = num7;
                }
                if (duration != 0L)
                {
                    long num8 = time2._endTime - num3;
                    if (duration < num8)
                    {
                        num8 = duration;
                    }
                    duration -= num8;
                    oneDay = num3 + num8;
                }
                if (duration == 0L)
                {
                    break;
                }
            }
            return new DateTime(num2 + oneDay);
        }

        public virtual object Clone()
        {
            CalendarPeriod period = (CalendarPeriod) base.MemberwiseClone();
            period._workingTimes = new List<WorkingTime>(2);
            foreach (WorkingTime time in this._workingTimes)
            {
                period._workingTimes.Add(time.Clone() as WorkingTime);
            }
            return period;
        }

        public WorkingTime[] GetWorkingTimes()
        {
            WorkingTime[] timeArray = new WorkingTime[this._workingTimes.Count];
            int num = 0;
            foreach (WorkingTime time in this._workingTimes)
            {
                timeArray[num++] = (WorkingTime) time.Clone();
            }
            return timeArray;
        }

        public bool Is24HoursWork()
        {
            if (!this._isWorking)
            {
                return false;
            }
            if (this._workingTimes.Count != 1)
            {
                return false;
            }
            WorkingTime time = this._workingTimes[0];
            return ((time._startTime == 0L) && (time._endTime == WorkCalendar.OneDay));
        }

        internal DateTime NextNonWorkingTimeFromWT(DateTime d, out bool nonworking)
        {
            DateTime date = d.Date;
            TimeSpan span = (TimeSpan) (d - date);
            foreach (WorkingTime time2 in this._workingTimes)
            {
                if (span < time2.EndTime)
                {
                    nonworking = true;
                    if (span < time2.StartTime)
                    {
                        return d;
                    }
                    return (date + time2.EndTime);
                }
            }
            if (this._workingTimes[this._workingTimes.Count - 1]._endTime == WorkCalendar.OneDay)
            {
                nonworking = false;
                return d;
            }
            nonworking = true;
            return d;
        }

        internal DateTime NextWorkingTimeFromWT(DateTime dateTime, out bool working)
        {
            long ticks = dateTime.Ticks;
            long num2 = ticks - (ticks % 0xc92a69c000L);
            long num3 = ticks - num2;
            int count = this._workingTimes.Count;
            for (int i = 0; i < count; i++)
            {
                WorkingTime time = this._workingTimes[i];
                if (num3 < time._endTime)
                {
                    working = true;
                    long num6 = time._startTime;
                    if (num3 < num6)
                    {
                        return new DateTime(num2 + num6);
                    }
                    return dateTime;
                }
            }
            working = false;
            return new DateTime(num2 + WorkCalendar.OneDay);
        }

        internal DateTime PreviousWorkingTimeFromWT(DateTime d, out bool working)
        {
            long ticks = d.Ticks;
            long num2 = ticks - (ticks % 0xc92a69c000L);
            long oneDay = ticks - num2;
            if (oneDay == 0L)
            {
                oneDay = WorkCalendar.OneDay;
                num2 -= WorkCalendar.OneDay;
            }
            for (int i = this._workingTimes.Count - 1; i >= 0; i--)
            {
                WorkingTime time = this._workingTimes[i];
                if (oneDay > time._startTime)
                {
                    working = true;
                    if (oneDay >= time._endTime)
                    {
                        return new DateTime(num2 + time._endTime);
                    }
                    return d;
                }
            }
            working = false;
            return new DateTime(num2);
        }

        internal abstract DateTime Remove(DateTime time, ref long duration);
        internal DateTime RemoveWorkInDay(DateTime time, ref long duration)
        {
            if (duration == 0L)
            {
                return time;
            }
            if (!this._isWorking)
            {
                return time.Date;
            }
            DateTime date = time.Date;
            TimeSpan span = (TimeSpan) (time - date);
            long ticks = span.Ticks;
            if (ticks == 0L)
            {
                ticks = WorkCalendar.OneDay;
                date = date.AddDays(-1.0);
            }
            long num2 = 0L;
            bool flag = true;
            for (int i = this._workingTimes.Count - 1; i >= 0; i--)
            {
                WorkingTime time3 = this._workingTimes[i];
                if (flag)
                {
                    if (ticks <= time3._startTime)
                    {
                        continue;
                    }
                    flag = false;
                    if (ticks > time3._endTime)
                    {
                        ticks = time3._endTime;
                    }
                }
                else
                {
                    ticks = time3._endTime;
                }
                if (duration != 0L)
                {
                    long num4 = ticks - time3._startTime;
                    if (duration < num4)
                    {
                        num4 = duration;
                    }
                    duration -= num4;
                    num2 = ticks - num4;
                }
                if (duration == 0L)
                {
                    break;
                }
            }
            return date.AddTicks(num2);
        }

        internal bool SameWorkingTimes(CalendarPeriod p)
        {
            int count = this._workingTimes.Count;
            if (count != p.WorkingTimes.Count)
            {
                return false;
            }
            for (int i = 0; i < count; i++)
            {
                WorkingTime time = this._workingTimes[i];
                WorkingTime time2 = p._workingTimes[i];
                if ((time.StartTime != time2.StartTime) || (time.EndTime != time2.EndTime))
                {
                    return false;
                }
            }
            return true;
        }

        internal abstract long WorkBetween(DateTime time, DateTime end);
        internal long WorkBetweenHours(DateTime t1, DateTime t2)
        {
            DateTime date = t1.Date;
            if ((date != t2.Date) && (date.AddDays(1.0) != t2))
            {
                throw new ArgumentException();
            }
            if (t1 > t2)
            {
                throw new ArgumentException();
            }
            if (!this._isWorking || (t1 == t2))
            {
                return 0L;
            }
            TimeSpan span = (TimeSpan) (t1 - date);
            long ticks = span.Ticks;
            TimeSpan span2 = (TimeSpan) (t2 - date);
            long num2 = span2.Ticks;
            long num3 = 0L;
            int count = this._workingTimes.Count;
            for (int i = 0; i < count; i++)
            {
                WorkingTime time2 = this._workingTimes[i];
                long num6 = time2._startTime;
                long num7 = time2._endTime;
                if (ticks < num7)
                {
                    if (ticks < num6)
                    {
                        ticks = num6;
                    }
                    if (num2 < num6)
                    {
                        num2 = num6;
                    }
                    if (num2 <= num7)
                    {
                        return (num3 + (num2 - ticks));
                    }
                    num3 += num7 - ticks;
                    ticks = num7;
                }
            }
            return num3;
        }

        public System.Globalization.Calendar Calendar
        {
            get
            {
                return this._calendar._calendar;
            }
        }

        public bool IsWorking
        {
            get
            {
                return this._isWorking;
            }
            set
            {
                this._isWorking = value;
            }
        }

        internal bool Standard
        {
            get
            {
                return this._standard;
            }
            set
            {
                this._standard = value;
            }
        }

        public IList<WorkingTime> WorkingTimes
        {
            get
            {
                return this._workingTimes;
            }
        }

        public long WorkInOneDay
        {
            get
            {
                if (!this._isWorking)
                {
                    return 0L;
                }
                long num = 0L;
                int count = this._workingTimes.Count;
                for (int i = 0; i < count; i++)
                {
                    num += this._workingTimes[i].Duration;
                }
                return num;
            }
        }
    }
}

